package com.ysstech.finance.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ysstech.common.entity.PageBean;
import com.ysstech.common.enums.YssEnum;
import com.ysstech.common.exception.BusinessException;
import com.ysstech.common.service.DicvalueService;
import com.ysstech.common.service.HolidayService;
import com.ysstech.common.util.DateUtil;
import com.ysstech.finance.entity.Balance;
import com.ysstech.finance.entity.Subject;
import com.ysstech.finance.entity.Voucher;
import com.ysstech.finance.enums.FinanceEnum;
import com.ysstech.finance.mapper.BalanceMapper;
import com.ysstech.finance.service.BalanceService;
import com.ysstech.finance.service.SubjectService;
import com.ysstech.finance.service.VoucherService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lishuangliang
 * @since 2021-04-01
 */
@Slf4j
@Service
public class BalanceServiceImpl extends ServiceImpl<BalanceMapper, Balance> implements BalanceService {
    @Autowired
    private VoucherService voucherService;
    @Autowired
    private BalanceMapper balanceMapper;
    @Autowired
    private HolidayService holidayService;
    @Autowired
    private SubjectService subjectService;
    @Autowired
    protected DicvalueService dicValueService;

    /**
     * 查询余额表列表信息
     *
     * @param balance
     * @param pageBean
     * @return
     * @throws Exception
     */
    public PageBean<Balance> queryAllBalance(Balance balance, PageBean pageBean) throws Exception {
        QueryWrapper<Balance> wrapper = this.getQueryWrapper(balance);
        IPage pageBalance = balanceMapper.queryBalance(new Page<>(pageBean.getPageNum(), pageBean.getPageSize()), wrapper);
        this.switchedListBalance(pageBalance.getRecords());
        return new PageBean<>(pageBalance);
    }

    /**
     * 类型，机构等中文的转换
     *
     * @param list
     * @return
     * @throws Exception
     */
    public List<Balance> switchedListBalance(List<Balance> list) throws Exception {
        Map<String, String> mapCurrency = dicValueService.getCacheDicValueMap(FinanceEnum.CURRENCY.getCode());
        for (Balance balance : list) {
            if (null == balance) {
                continue;
            }
            if (null != mapCurrency && mapCurrency.containsKey(balance.getCurrency())) {
                balance.setCurrency(mapCurrency.get(balance.getCurrency()));
            }
            // 明细科目open
            if ("0".equals(balance.getParentId())) {
                balance.set_parentId(null);
            } else {
                balance.set_parentId(balance.getParentId());
            }
            if (1 == balance.getDetailed()) {
                balance.setState("open");
            } else {
                balance.setState("closed");
            }
            balance.setChecked(false);
            balance.setIconCls("icon-bricks");
        }
        return list;
    }

    /**
     * 查询条件
     *
     * @param balance
     * @return
     * @throws Exception
     */
    private QueryWrapper<Balance> getQueryWrapper(Balance balance) throws Exception {
        QueryWrapper<Balance> wrapper = new QueryWrapper<>();
        //wrapper.orderByAsc("FDATE,ACCOUNT_ID,SUBJECT_ID,AUXILARY_CDOE");
        if (null == balance) {
            return wrapper;
        }
        if (StringUtils.isNotBlank(balance.getSelfdate())) {
            wrapper.eq("FDATE", balance.getSelfdate());
        }
        return wrapper;
    }

    /**
     * 查询明细的余额表数据，给估值表统计使用
     *
     * @param accountId
     * @param fdate
     * @return
     */
    @Override
    public List<Balance> queryBalanceByValuation(String accountId, LocalDate fdate) throws Exception {
        if (StringUtils.isBlank(accountId) || null == fdate) {
            throw new BusinessException("获取余额表数据失败，没有获取到基金编号和日期，请稍后重试！");
        }
        Balance balance = new Balance();
        balance.setAccountId(accountId);
        balance.setFdate(fdate);
        return balanceMapper.queryBalanceByValuation(balance);
    }

    /**
     * 生成余额表
     *
     * @param balance
     * @throws Exception
     */
    public void produceBalance(Balance balance) throws Exception {
        if (null == balance || StringUtils.isBlank(balance.getSelfdate()) || StringUtils.isBlank(balance.getAccountId())) {
            throw new BusinessException("生成余额表出错，没有获取到基金信息，请稍后重试！");
        }
        List<Balance> addlist = new ArrayList<>();
        //当天凭证发生数据
        Voucher voucher = new Voucher();
        voucher.setAccountId(balance.getAccountId());
        voucher.setFdate(DateUtil.strToLocalDate(balance.getSelfdate()));
        List<Voucher> list = voucherService.queryVoucherBalance(voucher);
        Map<String, Balance> map = this.queryBalanceYesterday(balance);
        if (!CollectionUtils.isEmpty(list)) {
            for (Voucher bean : list) {
                if (null == bean) {
                    continue;
                }
                Balance addbalance = new Balance();
                addbalance.setId(DateUtil.generateUUID());
                // 来源于凭证
                addbalance.setSource(1);
                addbalance.setAccountId(balance.getAccountId());
                addbalance.setFdate(DateUtil.strToLocalDate(balance.getSelfdate()));
                if (map.containsKey(bean.getSubjectId())) {
                    Balance balance1 = map.get(bean.getSubjectId());
                    //今日的期初余额等于上一日的期末余额
                    addbalance.setBeginningBalance(balance1.getEndBalance());
                    //今日的期初数量等于上一日的期末数量
                    addbalance.setBeginningAmount(balance1.getEndAmount());
                    //上一日的累计借贷金额和数量
                    addbalance.setTotalCurrentCreditMoney(balance1.getTotalCurrentCreditMoney());
                    addbalance.setTotalCurrentDebitAmount(balance1.getTotalCurrentDebitAmount());
                    addbalance.setTotalCurrentDebitMoney(balance1.getTotalCurrentDebitMoney());
                    addbalance.setTotalCurrentCreditAmount(balance1.getTotalCurrentCreditAmount());
                }
                //借方发生
                addbalance.setCurrentDebitMoney(bean.getMoneyDr());
                addbalance.setCurrentDebitAmount(bean.getAmountDr());
                addbalance.setTotalCurrentCreditMoney(bean.getMoneyDr().add(addbalance.getTotalCurrentDebitMoney()));
                addbalance.setTotalCurrentDebitAmount(bean.getAmountDr().add(addbalance.getTotalCurrentCreditAmount()));
                //贷方发生
                addbalance.setCurrentCreditMoney(bean.getMoneyCr());
                addbalance.setCurrentCreditAmount(bean.getAmountCr());
                addbalance.setTotalCurrentDebitMoney(bean.getMoneyCr().add(addbalance.getTotalCurrentDebitMoney()));
                addbalance.setTotalCurrentCreditAmount(bean.getAmountCr().add(addbalance.getTotalCurrentCreditAmount()));

                addbalance.setSubjectId(bean.getSubjectId());
                addbalance.setCurrency(bean.getCurrency());
                if ("DR".equals(bean.getDrandcr())) { //科目是借方
                    addbalance.setEndAmount(addbalance.getBeginningAmount().add(addbalance.getCurrentDebitAmount().subtract(addbalance.getCurrentCreditAmount())));
                    addbalance.setEndBalance(addbalance.getBeginningBalance().add(addbalance.getCurrentDebitMoney().subtract(addbalance.getCurrentCreditMoney())));
                } else { //凭证是贷方
                    addbalance.setEndAmount(addbalance.getBeginningAmount().add(addbalance.getCurrentCreditAmount().subtract(addbalance.getCurrentDebitAmount())));
                    addbalance.setEndBalance(addbalance.getBeginningBalance().add(addbalance.getCurrentCreditMoney().subtract(addbalance.getCurrentDebitMoney())));
                }
                addbalance.setAddTime(LocalDateTime.now());
                addbalance.setSecuritiesCode(bean.getSecuritiesCode());
                addlist.add(addbalance);
            }
        }
        this.handleBalanceYesterday(map, list, addlist, balance);
        this.handleBalance(addlist);
    }

    /**
     * 处理昨日数据
     *
     * @throws Exception
     */
    private void handleBalanceYesterday(Map<String, Balance> map, List<Voucher> list, List<Balance> addlist, Balance balance) throws Exception {
        //循环昨日数据
        for (Map.Entry<String, Balance> info : map.entrySet()) {
            Balance balance1 = info.getValue();
            if (null == balance1) {
                continue;
            }
            balance1.setSelfdate(balance.getSelfdate());
            balance1.setAccountId(balance.getAccountId());
            // 今天的数据没有情况，直接把昨日数据拿过来作为今日数据
            if (CollectionUtils.isEmpty(list)) {
                Balance addbalance = getBalance(balance1);
                addlist.add(addbalance);
            }
            // 如果今天有数据，今日的凭证数据在昨日余额里有对应的值 这部分已经计算了。只是取昨天有今天没有发生的数据
            for (Voucher bean : list) {
                if (info.getKey().equals(bean.getSubjectId())) {
                    continue;
                }
                Balance addbalance = getBalance(balance1);
                addlist.add(addbalance);
            }
        }
    }

    private Balance getBalance(Balance balance) throws Exception {
        Balance addbalance = new Balance();
        addbalance.setId(DateUtil.generateUUID());
        // 来源于凭证
        addbalance.setSource(balance.getSource());
        addbalance.setAccountId(balance.getAccountId());
        addbalance.setFdate(DateUtil.strToLocalDate(balance.getSelfdate()));
        //今日的期初余额等于上一日的期末余额
        addbalance.setBeginningBalance(balance.getEndBalance());
        //今日的期初数量等于上一日的期末数量
        addbalance.setBeginningAmount(balance.getEndAmount());
        //上一日的累计借贷金额和数量
        addbalance.setTotalCurrentCreditMoney(balance.getTotalCurrentCreditMoney());
        addbalance.setTotalCurrentDebitAmount(balance.getTotalCurrentDebitAmount());
        addbalance.setTotalCurrentDebitMoney(balance.getTotalCurrentDebitMoney());
        addbalance.setTotalCurrentCreditAmount(balance.getTotalCurrentCreditAmount());
        //借方发生
        addbalance.setCurrentDebitMoney(BigDecimal.ZERO);
        addbalance.setCurrentDebitAmount(BigDecimal.ZERO);
        //贷方发生
        addbalance.setCurrentCreditMoney(BigDecimal.ZERO);
        addbalance.setCurrentCreditAmount(BigDecimal.ZERO);
        addbalance.setCurrency(balance.getCurrency());
        addbalance.setSubjectId(balance.getSubjectId());
        addbalance.setEndAmount(balance.getEndAmount());
        addbalance.setEndBalance(balance.getEndBalance());
        addbalance.setAddTime(LocalDateTime.now());
        addbalance.setSecuritiesCode(balance.getSecuritiesCode());
        return addbalance;
    }

    /**
     * 获取昨日的明细科目的数据
     *
     * @param balance
     * @return
     * @throws Exception
     */
    private Map<String, Balance> queryBalanceYesterday(Balance balance) throws Exception {
        //删除当天余额表数据
        QueryWrapper<Balance> wrapperdel = new QueryWrapper<>();
        wrapperdel.eq("FDATE", DateUtil.strToLocalDate(balance.getSelfdate()));
        wrapperdel.eq("ACCOUNT_ID", balance.getAccountId());
        this.remove(wrapperdel);
        //上一日余额表数据 科目表里最明细科目的数据
        String yesterdate = holidayService.getNextWorkday(balance.getSelfdate(), -1);
        QueryWrapper<Balance> wrapper = new QueryWrapper<>();
        wrapper.eq("FDATE", DateUtil.strToLocalDate(yesterdate));
        wrapper.eq("ACCOUNT_ID", balance.getAccountId());
        List<Balance> balanceList = balanceMapper.queryBalanceYesterday(wrapper);
        Map<String, Balance> map = new HashMap<>();
        for (Balance balanceDetaild : balanceList) {
            map.put(balanceDetaild.getSubjectId(), balanceDetaild);
        }
        return map;
    }

    /**
     * 余额表将明细数据汇总上去
     */
    private void handleBalance(List<Balance> addlist) throws Exception {
        if (CollectionUtils.isEmpty(addlist)) {
            return;
        }
        // 获取所有科目信息
        Map<String, Subject> mapSub = subjectService.getSubjectMap();
        if (CollectionUtils.isEmpty(mapSub)) {
            return;
        }
        Map<String, Balance> map = new HashMap<>();
        // 汇集上级科目
        for (Balance bal : addlist) {
            if (null == bal) {
                continue;
            }
            recursionAdjust(bal, mapSub, map);
        }
        for (Map.Entry<String, Balance> info : map.entrySet()) {
            if (null == info.getValue()) {
                continue;
            }
            addlist.add(info.getValue());
        }
        this.saveBatch(addlist);
    }

    private void recursionAdjust(Balance balance, Map<String, Subject> subMap, Map<String, Balance> map) throws Exception {
        Subject subject = subMap.get(balance.getSubjectId());
        if (null == subject) {
            return;
        }
        String parentId = subject.getParentId();
        if ("0".equals(parentId)) {
            return;
        }
        if (map.containsKey(parentId)) { // 已经存在上级科目
            Balance bean = map.get(parentId);
            bean.setEndBalance(bean.getEndBalance().add(balance.getEndBalance()));
            bean.setEndAmount(bean.getEndAmount().add(balance.getEndAmount()));
            //借方发生
            bean.setCurrentDebitMoney(bean.getCurrentDebitMoney().add(balance.getCurrentDebitMoney()));
            bean.setCurrentDebitAmount(bean.getCurrentDebitAmount().add(balance.getCurrentDebitAmount()));
            bean.setTotalCurrentCreditMoney(bean.getTotalCurrentCreditMoney().add(balance.getTotalCurrentCreditMoney()));
            bean.setTotalCurrentDebitAmount(bean.getTotalCurrentDebitAmount().add(balance.getTotalCurrentDebitAmount()));
            //贷方发生
            bean.setCurrentCreditMoney(bean.getCurrentCreditMoney().add(balance.getCurrentCreditMoney()));
            bean.setCurrentCreditAmount(bean.getCurrentCreditAmount().add(balance.getCurrentCreditAmount()));
            bean.setTotalCurrentDebitMoney(bean.getTotalCurrentDebitMoney().add(balance.getTotalCurrentDebitMoney()));
            bean.setTotalCurrentCreditAmount(bean.getTotalCurrentCreditAmount().add(balance.getTotalCurrentCreditAmount()));
            map.put(parentId, bean);
            recursionAdjust(bean, subMap, map);
        } else {
            Balance sumBalance = new Balance();
            sumBalance.setId(DateUtil.generateUUID());
            sumBalance.setSource(1);
            sumBalance.setCurrency(balance.getCurrency());
            sumBalance.setAccountId(balance.getAccountId());
            sumBalance.setFdate(balance.getFdate());
            sumBalance.setEndBalance(balance.getEndBalance());
            sumBalance.setEndAmount(balance.getEndAmount());
            //借方发生
            sumBalance.setCurrentDebitMoney(balance.getCurrentDebitMoney());
            sumBalance.setCurrentDebitAmount(balance.getCurrentDebitAmount());
            sumBalance.setTotalCurrentCreditMoney(balance.getTotalCurrentCreditMoney());
            sumBalance.setTotalCurrentDebitAmount(balance.getTotalCurrentDebitAmount());
            //贷方发生
            sumBalance.setCurrentCreditMoney(balance.getCurrentCreditMoney());
            sumBalance.setCurrentCreditAmount(balance.getCurrentCreditAmount());
            sumBalance.setTotalCurrentDebitMoney(balance.getTotalCurrentDebitMoney());
            sumBalance.setTotalCurrentCreditAmount(balance.getTotalCurrentCreditAmount());
            sumBalance.setAddTime(LocalDateTime.now());
            sumBalance.setSubjectId(parentId);
            map.put(parentId, sumBalance);
            recursionAdjust(sumBalance, subMap, map);
        }
    }
}
